package cn.easier.activity.console.service.impl;

import cn.easier.activity.console.entity.LogCountParams;
import cn.easier.activity.console.entity.LogsCount;
import cn.easier.activity.console.entity.SignMessageParams;
import cn.easier.activity.console.repository.*;
import cn.easier.activity.console.service.DataStatisticsService;
import cn.easier.activity.console.vo.Datas;
import cn.easier.activity.web.dto.ActivityRecordDto;
import cn.easier.activity.web.entity.*;
import cn.easier.club.base.dto.ResultInfo;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author lixiaopeng
 */
@Service
public class DataStatisticsServiceImp implements DataStatisticsService {

    private Logger log = LoggerFactory.getLogger(DataStatisticsServiceImp.class);

    @Resource
    private ActivityInfoRepository activityInfoRepository;

    @Resource
    private ActivityRecordStatisticsRepository activityRecordStatisticsRepository;

    @Resource
    private LogsCountRepository logsCountRepository;

    @Resource
    private ActivityCouponCodeRepository activityCouponCodeRepository;

    @Resource
    private ActivityPrizeRepository activityPrizeRepository;

    @Override
    public List<ActivityInfo> getAllActivity() {
        return activityInfoRepository.findByStatus(2);
    }

    @Override
    public List<ActivityInfo> getAllActivityByUser(String username) {
        return activityInfoRepository.findByCreateByAndCreateTimeAndStatus(username, 2);
    }

    @Override
    public ResultInfo findAllByConditions(Integer activityId, String phoneNum, int begin, int count) {
        ResultInfo resultInfo;
        try {
            Pageable pageList = new PageRequest(begin, count, new Sort(Sort.Direction.DESC, "createDate"));
            Page<ActivityRecord> page = activityRecordStatisticsRepository
                    .findAll(getActivityInfosByConditions(activityId, phoneNum, "", null), pageList);
            log.info("条件查询中奖信息条数-->{}", page.getTotalElements());
            resultInfo = new ResultInfo(String.valueOf(HttpServletResponse.SC_OK),
                    String.valueOf(page.getTotalElements()), page.getContent());
        } catch (Exception e) {
            log.info("条件查询中奖信息失败=>{}", e.getMessage());
            resultInfo = new ResultInfo("ERROR", "条件查询中奖信息失败", null);
        }
        return resultInfo;
    }

    @Override
    public ResultInfo findAllByConditionsAndUser(String username, Integer activityId, String phoneNum, String recordNo, Integer prizeType, int begin, int count) {
        try {
            int pageCount = begin * count;
            List<ActivityInfo> byCreateBy = Lists.newArrayList();
            if (null != username) {
                byCreateBy = activityInfoRepository.findByCreateByAndCreateTimeAndStatus(username, 2);
            } else {
                byCreateBy = activityInfoRepository.findByStatus(2);
            }
            List<Integer> idList = new ArrayList<>();
            for (ActivityInfo activityInfo : byCreateBy) {
                idList.add(activityInfo.getId());
            }
            List<ActivityRecord> by = activityRecordStatisticsRepository.findBy(activityId, phoneNum, recordNo, prizeType, idList, pageCount, count);
            long byCount = activityRecordStatisticsRepository.findByCount(activityId, phoneNum, recordNo, prizeType, idList);
            List<ActivityRecordDto> returnList = addCouponCodeMessage(by);
            log.info("条件查询中奖信息条数-->{}", byCount);
            return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), String.valueOf(byCount), returnList);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("条件查询中奖信息失败=>{}", e.getMessage());
            return new ResultInfo("ERROR", "条件查询中奖信息失败", null);
        }
    }

    @Override
    public Page<Datas> findAllDataList(int pageNum, int pageSize, Integer activityId, String username) {
        PageRequest pageRequest = new PageRequest(pageNum, pageSize);
        final ArrayList<Integer> ids = new ArrayList<>();
        List<ActivityInfo> activityInfoList = Lists.newArrayList();
        if (username != null) {
            activityInfoList = activityInfoRepository.findByCreateByAndCreateTimeAndStatus(username, 2);
            for (ActivityInfo activityInfo : activityInfoList) {
                ids.add(activityInfo.getId());
            }
            if (CollectionUtils.isEmpty(ids)) {
                return new PageImpl<>(new ArrayList<>(), pageRequest, 0L);
            }
        } else {
            activityInfoList = activityInfoRepository.findByStatus(2);
            for (ActivityInfo activityInfo : activityInfoList) {
                ids.add(activityInfo.getId());
            }
            if (CollectionUtils.isEmpty(ids)) {
                return new PageImpl<>(new ArrayList<>(), pageRequest, 0L);
            }
        }
        Page<LogsCount> all = logsCountRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (activityId != null) {
                predicates.add(cb.equal(root.get("activityId").as(String.class), activityId));
            }
            if (username != null) {
                predicates.add(cb.and(root.get("activityId").in(ids)));
            }
            predicates.add(cb.isNull(root.get("day")));
            query.orderBy(cb.desc(root.get("activityId").as(Integer.class)));
            Predicate[] p = new Predicate[predicates.size()];
            return cb.and(predicates.toArray(p));
        }, pageRequest);
        List<LogsCount> content = all.getContent();
        ArrayList<Datas> datasList = new ArrayList<>();
        for (LogsCount count : content) {
            Datas datas = new Datas();
            BeanUtils.copyProperties(count, datas);
            datas.setCountBill(count.getPrizeScore());
            datasList.add(datas);
        }
        return new PageImpl<>(datasList, pageRequest, all.getTotalElements());
    }

    @Override
    public List<SignMessageParams> exportBySignMessage() {
        List<SignMessageParams> returnList = new ArrayList<>();
        List<Object[]> byCountForSignMessage = activityRecordStatisticsRepository.findByCountForSignMessage();
        for (Object[] objects : byCountForSignMessage) {
            String projectName = "";
            String roomName = "";
            StringBuilder projectMessage = new StringBuilder();
            SignMessageParams params = new SignMessageParams();
            params.setActivityId(((Integer) objects[0]).toString());
            params.setActivityName((String) objects[1]);
            params.setPhoneNum(((String) objects[2]));
            params.setCreateTime(objects[3].toString().substring(0, 19));
            params.setPrizeName((String) objects[4]);
            String s = objects[5].toString();
            JSONArray jsonArray = JSONArray.parseArray(s);
            for (int i = 0; i < jsonArray.size(); i++) {
                Object o = jsonArray.get(i);
                JSONObject message = JSONObject.parseObject(o.toString());
                if (StringUtils.isNotBlank((String) message.get("projectName"))) {
                    projectName = (String) message.get("projectName");
                }
                if (StringUtils.isNotBlank((String) message.get("roomName"))) {
                    roomName = (String) message.get("roomName");
                }
                projectMessage.append("{项目名称:").append(projectName).append(" ").append("房屋名称:").append(roomName).append("},");

            }
            params.setProjectName(projectMessage.toString());
            returnList.add(params);
        }
        return returnList;
    }

    @Override
    public ResultInfo updateEntityStrategy(List<String> recordIdList) {
        List<ActivityRecord> byRecordNo = activityRecordStatisticsRepository.findByRecordNo(recordIdList);
        for (ActivityRecord record : byRecordNo) {
            if (record == null) {
                log.error("修改发货状态出错,未查询到中奖信息-->{}", record.getRecordNo());
                return new ResultInfo("ERROR", "未查询到中奖信息", null);
            }

            if (!record.getPrizeType().equals(PrizeType.ENTITY_GIFFT)) {
                log.error("修改发货状态出错,中奖奖品不是实物礼品-->{}", record.getRecordNo());
                return new ResultInfo("ERROR", "中奖奖品不是实物礼品", null);
            }
            if (record.getExchangeState().equals(ExchangeState.EXCHANGE_COMPLETE)) {
                log.error("修改发货状态出错,已经兑换过中奖奖品-->{}", record.getRecordNo());
                return new ResultInfo("ERROR", "已经兑换过中奖奖品", null);
            }
            record.setExchangeState(ExchangeState.EXCHANGE_COMPLETE);
            activityRecordStatisticsRepository.save(record);
        }
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "批量发货完成", null);
    }

    @Override
    public List<ActivityRecordDto> exportByConditions(Integer activityId, String phoneNum, String recordNo, Integer prizeType) throws Exception {
        List<ActivityRecord> recordList = new ArrayList<>();
        if (prizeType == null) {
            prizeType = 0;
        }
        if (activityId == null && StringUtils.isBlank(phoneNum) && StringUtils.isBlank(recordNo)) {
            recordList = activityRecordStatisticsRepository.findBy1(prizeType);
        } else {
            Specification<ActivityRecord> activityInfosByConditions = getActivityInfosByConditions(activityId, phoneNum, recordNo, prizeType);
            recordList = activityRecordStatisticsRepository.findAll(activityInfosByConditions, new Sort(Sort.Direction.DESC, "createDate"));
        }
        return addCouponCodeMessage(recordList);
    }

    @Override
    public List<ActivityRecordDto> exportByConditionsAndUser(Integer activityId, String phoneNum, String username, String recordNo, Integer prizeType) throws Exception {
        List<ActivityInfo> byCreateBy = activityInfoRepository.findByCreateByAndCreateTime(username);
        List<Integer> idList = new ArrayList<>();
        for (ActivityInfo activityInfo : byCreateBy) {
            idList.add(activityInfo.getId());
        }
        List<ActivityRecord> byCountForExport = activityRecordStatisticsRepository.findByCountForExport(activityId, phoneNum, recordNo, prizeType, idList);
        return addCouponCodeMessage(byCountForExport);
    }

    @Override
    public ResultInfo findDayData(String activityId, int pageNum, int pageSize) {
        ResultInfo resultInfo;
        Pageable pageList = new PageRequest(pageNum, pageSize, new Sort(Sort.Direction.DESC, "day"));
        try {
            Specification<LogsCount> specification = getDataByConditions(activityId);
            Page<LogsCount> page = logsCountRepository.findAll(specification, pageList);
            log.info("查询活动日详情数据条数-->{}", page.getTotalElements());
            List<LogsCount> countList = page.getContent();
            List<LogCountParams> returnList = new ArrayList<>();
            for (LogsCount logsCount : countList) {
                LogCountParams countParams = new LogCountParams();
                BeanUtils.copyProperties(logsCount, countParams);
                countParams.setCountBill(logsCount.getPrizeScore());
                returnList.add(countParams);
            }
            resultInfo = new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), String.valueOf(page.getTotalElements()), returnList);
        } catch (Exception e) {
            log.error("查询活动日详情数据异常=>{}", e.getMessage());
            resultInfo = new ResultInfo("ERROR", "查询活动日详情数据异常", null);
        }
        return resultInfo;
    }

    @Override
    public List<LogCountParams> exportDayData(String activityId) {
        Specification<LogsCount> specification = getDataByConditions(activityId);
        List<LogsCount> day = logsCountRepository.findAll(specification, new Sort(Sort.Direction.DESC, "day"));
        List<LogCountParams> returnList = new ArrayList<>();
        for (LogsCount logsCount : day) {
            LogCountParams params = new LogCountParams();
            BeanUtils.copyProperties(logsCount, params);
            params.setCountBill(logsCount.getPrizeScore());
            returnList.add(params);
        }
        return returnList;
    }

    private Specification<ActivityRecord> getActivityInfosByConditions(Integer activityId, String phoneNum, String recordNo, Integer prizeType) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (null != activityId) {
                predicates.add(cb.equal(root.get("activityId").as(Integer.class), activityId));
            }
            if (StringUtils.isNotEmpty(phoneNum)) {
                predicates.add(cb.equal(root.get("phoneNum").as(String.class), phoneNum));
            }
            if (StringUtils.isNotEmpty(recordNo)) {
                predicates.add(cb.equal(root.get("recordNo").as(String.class), recordNo));
            }
            if (0 != prizeType) {
                predicates.add(cb.equal(root.get("prizeType").as(Integer.class), prizeType));
            }
            Predicate[] p = new Predicate[predicates.size()];
            return cb.and(predicates.toArray(p));
        };
    }

    private Specification<LogsCount> getDataByConditions(String activityId) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("activityId").as(String.class), activityId));
            predicates.add(cb.isNotNull(root.get("day")));
            Predicate[] p = new Predicate[predicates.size()];
            return cb.and(predicates.toArray(p));
        };
    }

    private List<ActivityRecordDto> addCouponCodeMessage(List<ActivityRecord> recordList) {
        List<ActivityRecordDto> returnList = new ArrayList<>();
        List<Integer> couponCodeIdList = new ArrayList<>();
        List<ActivityCouponCode> all = new ArrayList<>();
        Set<Integer> prizeIdList = new HashSet<>();
        HashMap<Integer, String> prizeIdMap = new HashMap<>();
        for (ActivityRecord record : recordList) {
            prizeIdList.add(record.getPrizeId());
        }
        List<ActivityPrize> prizeList = activityPrizeRepository.findAll(prizeIdList);
        for (ActivityPrize prize : prizeList) {
            if (prize.getPrizeType().equals(PrizeType.ELECTRONIC_COUPON) && StringUtils.isNotBlank(prize.getUrl())) {
                prizeIdMap.put(prize.getId(), prize.getUrl());
            }
        }
        for (ActivityRecord record : recordList) {
            if (record.getCouponCodeId() != null) {
                couponCodeIdList.add(record.getCouponCodeId());
            }
        }
        if (CollectionUtils.isNotEmpty(couponCodeIdList)) {
            all = activityCouponCodeRepository.findAll(couponCodeIdList);
        }
        for (ActivityRecord record : recordList) {
            ActivityRecordDto dto = new ActivityRecordDto();
            BeanUtils.copyProperties(record, dto);
            if (CollectionUtils.isNotEmpty(all)) {
                for (ActivityCouponCode couponCode : all) {
                    if (record.getCouponCodeId() != null) {
                        if (record.getCouponCodeId().equals(couponCode.getId())) {
                            if (couponCode.getCouponType().equals(CouponType.URL) || couponCode.getCouponType().equals(CouponType.KEY)) {
                                dto.setCouponCodeMessage(couponCode.getCode());
                            } else {
                                dto.setCouponCodeMessage(couponCode.getCode() + "," + couponCode.getSecretKey());
                            }
                        }
                    }else {
                        addCodeMessage(prizeIdMap,record,dto);
                    }
                }
            }else {
                addCodeMessage(prizeIdMap,record,dto);
            }
            returnList.add(dto);
        }
        return returnList;
    }

    private ActivityRecordDto addCodeMessage(HashMap<Integer, String> prizeIdMap ,ActivityRecord record,ActivityRecordDto dto) {
        Iterator<Map.Entry<Integer, String>> iterator = prizeIdMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> entry = iterator.next();
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            if (entry.getKey().equals(record.getPrizeId())) {
                dto.setCouponCodeMessage(entry.getValue());
            }
        }
        return dto;
    }
}
